﻿using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Net;
using System.Text;
using System.Threading;

namespace Vkontakte.Api.Operations
{
	public class BaseApiOperation
		:IAsyncResult
	{
		private List<string> _names = new List<string>();
		private List<string> _params = new List<string>();
		private string _url;
		private string _result;
		private HttpWebRequest _webRequest;
		private ManualResetEvent _event = new ManualResetEvent(false);
		private ApiError _errorCode = ApiError.NotReady;
		private string _apiVersion;

		protected BaseApiOperation(string apiVersion)
		{
			_apiVersion = apiVersion;
		}

		protected void AddParameter(string name,string value)
		{
			_names.Add(name);
			_params.Add(value);
		}

		protected virtual void Compile()
		{
			AddParameter("v", _apiVersion);
		}


		internal void Start(long appid,long userid,string sid,string secret)
		{
			AddParameter("api_id", appid.ToString());
			Compile();
			_url = Utils.MakeQuerry(userid, _names, _params, sid, secret);
			_names.Clear();
			_params.Clear();
			_webRequest = (HttpWebRequest) WebRequest.Create(_url);
			// См пример на www.know24.net
			_webRequest.UserAgent="Mozilla/4.0";
			_webRequest.Headers.Add("Accept-Encoding", "gzip, deflate");
			_webRequest.BeginGetResponse(GetResponceCallback, null);
		}

		private void GetResponceCallback(IAsyncResult result)
		{
			try
			{
				WebResponse response = _webRequest.EndGetResponse(result);
				Stream s = GetDecodedResponseStream( response );
				StreamReader reader = new StreamReader(s, Encoding.UTF8);
				_result = reader.ReadToEnd();
				_event.Set();
				s.Close();
				response.Close();
				_webRequest = null;

				// check on error
				int start = _result.IndexOf('\n');
				if (_result.Substring(start + 1).StartsWith("<error>"))
				{
					ErrorResponce err = Serializer.LoadObjectXmlString<ErrorResponce>(_result);
					_errorCode = err.Error;
				}
				else
				{
					_errorCode = ApiError.None;
					ParseData(_result);
				}
			}
			catch ( Exception )
			{
				_errorCode = ApiError.UnknownError;
			}


			if (Completed != null)
			{
				Completed();
			}
		}


		private static Stream GetDecodedResponseStream(WebResponse response)
		{
			var contentEncoding = response.Headers[ "Content-Encoding" ];
			if (!string.IsNullOrEmpty( contentEncoding ))
			{
				if (contentEncoding.ToLower().Contains( "gzip" ))
				{
					return new System.IO.Compression.GZipStream( response.GetResponseStream(), CompressionMode.Decompress );
				}
				if (contentEncoding.ToLower().Contains( "deflate" ))
				{
					return new System.IO.Compression.DeflateStream(response.GetResponseStream(), CompressionMode.Decompress);
				}
			}

			return response.GetResponseStream();
		}

		protected virtual void ParseData(string data)
		{

		}

		internal protected virtual bool CheckParams()
		{
			return false;
		}

	
		public object AsyncState
		{
			get { return _result; }
		}

		public WaitHandle AsyncWaitHandle
		{
			get { return _event; }
		}

		public bool CompletedSynchronously
		{
			get { return false; }
		}

		public bool IsCompleted
		{
			get { return _errorCode != ApiError.NotReady; }
		}

		public ApiError ErrorCode { get { return _errorCode; } }

		public event Action Completed;

	}

	public class Base20ApiOperation
	: BaseApiOperation
	{
		public Base20ApiOperation()
			: base("2.0")
		{

		}

		protected internal override bool CheckParams()
		{
			return false;
		}
	}

	public class Base30ApiOperation
		: BaseApiOperation
	{
		public Base30ApiOperation()
			: base("3.0")
		{

		}

		protected internal override bool CheckParams()
		{
			return true;
		}
	}

}